`timescale 1ns/1ns

`ifdef RenaCoreV2
`define  WBU RENA.CPU.rena_v2_core.WBU
`endif
// import "DPI-C" function void init_sd(string img);
import "DPI-C" function void init_ram(string img);

module tb_Rena;

reg        clk   ;
reg        rst_n ;
wire       sd_clk;
wire       sd_cmd;
wire [3:0] sd_dat;
wire       uart_eco;

string mem_file;
string sd_file;
initial begin
  clk   = 0;
  rst_n = 0;
  // enable vcd waveform
  if ($test$plusargs("dump-vcd")) begin
    $dumpfile("simv.vcd");
    $dumpvars(0,tb_Rena);
    $vcdpluson;
  end
  // enable fsdb waveform
  if ($test$plusargs("dump-fsdb")) begin
    $fsdbDumpfile("simv.fsdb");
    $fsdbDumpvars("+all"); 
    // $fsdbDumpvars;
  end
  // workload: bin file  DDR
  if ($test$plusargs("ddr")) begin
    $value$plusargs("ddr=%s", mem_file);
    init_ram(mem_file);
  end
  // if ($test$plusargs("sd")) begin
  //   $value$plusargs("sd=%s", sd_file);
  //   init_sd(sd_file);
  // end
  
  // start running 
  #100 rst_n = 1;
  $display("\nSimulation start running...");
end

always #5 clk = ~clk;     // 100MHz

Rena RENA(
  .clk  (clk  ),
  .rst_n(rst_n),
  // UART0
  .uart_rx(uart_eco),
  .uart_tx(uart_eco),
  // SPI
  .spi_clk  (  ),
  .spi_csn0 (  ),
  .spi_csn1 (  ),
  .spi_csn2 (  ),
  .spi_csn3 (  ),
  .spi_sdo0 (  ),
  .spi_sdo1 (  ),
  .spi_sdo2 (  ),
  .spi_sdo3 (  ),
  .spi_oe0  (  ),
  .spi_oe1  (  ),
  .spi_oe2  (  ),
  .spi_oe3  (  ),
  .spi_sdi0 ( 1'b0 ),
  .spi_sdi1 ( 1'b0 ),
  .spi_sdi2 ( 1'b0 ),
  .spi_sdi3 ( 1'b0 )
);  

`ifdef RenaCoreV2
`ifdef VIRTUAL_PRINT
always@(posedge clk)
  if((`WBU.q_exu_wbu_inst_i == 32'h7b) && `WBU.wbuValid)begin
    $fwrite(32'h8000_0001, "%c", `WBU.debug_a0);//TODO 这里可以直连到regfile里
    $fflush();
  end
`endif

reg [63:0] cycles;
reg [63:0] instrs;
always@(posedge clk)begin
  if(~rst_n)begin
      cycles <= 'd0;
      instrs <= 'd0;
  end else begin
      cycles <= cycles + 1;
      instrs <= instrs + `WBU.wbuValid;
  end
end
// 正常结束
always@(posedge clk)begin
  if(`WBU.wbuValid && (`WBU.q_exu_wbu_inst_i == 32'h00006b))begin
    $fwrite(32'h8000_0001,"HIT A GOOD TRAP\n");
    exitPrint(cycles,instrs);
    $finish;
  end else if(`WBU.wbuValid && (`WBU.q_exu_wbu_inst_i == 32'h00006f))begin
    $fwrite(32'h8000_0001,"HIT A SELF JUMP\n");
    exitPrint(cycles,instrs);
    $finish;
  end
end
// time out check
reg [13:0] TimeOutCheckValue=0; // 8192 = 2**14
always@(posedge clk or negedge rst_n)begin
  if(~rst_n)
    TimeOutCheckValue <= 'd0;
  else if(`WBU.wbuValid)
    TimeOutCheckValue <= 'd0;
  else 
    TimeOutCheckValue <= TimeOutCheckValue + 1'b1;
  
  if(TimeOutCheckValue >= 'd5000)begin
    $fwrite(32'h8000_0001,"!!! Time Out : 5000 cycle not commit, place check wave !!!\n");
    exitPrint(cycles,instrs);
    $finish;
  end
end

task exitPrint;
  input [63:0] cycles;
  input [63:0] instrs;
  begin
    real a = cycles;
    real b = instrs;
    real result = b / a;
    $fwrite(32'h8000_0001,"--> cycles:%10d || instrs:%10d  || IPC:%.4f \n\n\n",cycles,instrs,result);
  end
endtask

`endif

endmodule